<template>
    <div class="exam-paper-list">
        <el-card>
            <div style="margin-bottom: 16px">
                <el-button type="primary" @click="openAdd">新增试卷</el-button>
            </div>
            <el-table :data="list" style="width: 100%">
                <el-table-column prop="id" label="ID" width="60" />
                <el-table-column prop="title" label="试卷标题" />
                <el-table-column prop="question_count" label="题数" width="80" />
                <el-table-column prop="total_score" label="总分" width="80" />
                <el-table-column prop="duration" label="时长(分钟)" width="100" />
                <el-table-column label="操作" width="220">
                    <template #default="scope">
                        <el-button size="small" @click="openEdit(scope.row)">编辑</el-button>
                        <el-button size="small" @click="openDesign(scope.row)">组卷</el-button>
                        <el-button size="small" type="danger" @click="del(scope.row.id)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <el-pagination
                v-model:current-page="page"
                :page-size="20"
                :total="total"
                layout="total, prev, pager, next"
                @current-change="getList"
                style="margin-top: 16px"
            />
        </el-card>
        <el-dialog v-model="showForm" :title="form.id ? '编辑试卷' : '新增试卷'">
            <el-form :model="form" label-width="80px">
                <el-form-item label="标题">
                    <el-input v-model="form.title" />
                </el-form-item>
                <el-form-item label="时长">
                    <el-input-number v-model="form.duration" :min="1" />
                </el-form-item>
                <el-form-item label="说明">
                    <el-input v-model="form.description" type="textarea" />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="showForm = false">取消</el-button>
                <el-button type="primary" @click="submit">保存</el-button>
            </template>
        </el-dialog>
        <el-dialog v-model="showDesign" title="组卷" width="900px">
            <div style="margin-bottom: 8px">
                <el-radio-group v-model="designMode">
                    <el-radio label="manual">手动选题</el-radio>
                    <el-radio label="random">随机组卷</el-radio>
                </el-radio-group>
            </div>
            <div v-if="designMode === 'manual'">
                <el-row :gutter="16">
                    <el-col v-for="(qs, type) in questionBank" :key="type" :span="12">
                        <el-card :header="typeMap[type] || type" style="margin-bottom: 8px">
                            <div style="margin-bottom: 6px">
                                <el-input
                                    size="small"
                                    placeholder="搜索题目或解析"
                                    v-model="bankSearch[type]"
                                    @input="fetchPage(type, 1)"
                                    clearable
                                />
                            </div>
                            <div>
                                <div v-if="bankLoading[type]" style="padding: 12px 0; text-align: center; color: #999">正在加载...</div>
                                <div v-else>
                                    <div v-if="pagedBank(type).length === 0" style="padding: 12px 0; text-align: center; color: #999">暂无题目</div>
                                    <div v-else>
                                        <div v-for="q in pagedBank(type)" :key="q.id" style="padding: 6px 0; border-bottom: 1px solid #f2f2f2">
                                            <el-checkbox :label="q.id" v-model="selectedIds[type]">{{ q.content }}</el-checkbox>
                                        </div>
                                    </div>
                                </div>

                                <div style="text-align: center; margin-top: 8px">
                                    <el-pagination
                                        v-model:current-page="bankPage[type]"
                                        :page-size="bankPageSize"
                                        :total="bankTotalRemote[type] || bankTotal(type)"
                                        layout="prev, pager, next"
                                        @current-change="(p) => fetchPage(type, p)"
                                    />
                                </div>
                            </div>
                        </el-card>
                    </el-col>
                </el-row>
                <div style="margin: 8px 0">已选题目：</div>
                <div v-for="item in selectedTypes" :key="item.type" style="margin-bottom: 8px">
                    <b>{{ typeMap[item.type] || item.type }}：</b>
                    <div>
                        <div v-for="q in pagedSelected(item.type)" :key="q.id" style="padding: 4px 0">[{{ q.id }}] {{ q.content }}</div>
                    </div>
                    <div style="text-align: right">
                        <el-pagination
                            v-model:current-page="selPage[item.type]"
                            :page-size="selPageSize"
                            :total="(selectedIds[item.type] || []).length"
                            layout="prev, pager, next"
                        />
                    </div>
                </div>
                <el-button type="primary" @click="saveQuestions">保存组卷</el-button>
            </div>
            <div v-else>
                <el-form :model="randomForm" inline>
                    <el-form-item v-for="type in Object.keys(typeMap)" :key="type" :label="typeMap[type]">
                        <el-input-number v-model="randomForm[type]" :min="0" :max="bankTotalRemote[type] || (questionBank[type] || []).length" />
                    </el-form-item>
                </el-form>
                <el-button type="primary" @click="randomSelect">随机选题</el-button>
                <div style="margin: 8px 0">已选题目（按类别）：</div>
                <div v-for="item in selectedTypes" :key="item.type" style="margin-bottom: 8px">
                    <b>{{ typeMap[item.type] || item.type }}：</b>
                    <div>
                        <div v-for="q in pagedSelected(item.type)" :key="q.id" style="padding: 4px 0">[{{ q.id }}] {{ q.content }}</div>
                    </div>
                    <div style="text-align: right">
                        <el-pagination
                            v-model:current-page="selPage[item.type]"
                            :page-size="selPageSize"
                            :total="(selectedIds[item.type] || []).length"
                            layout="prev, pager, next"
                        />
                    </div>
                </div>
                <el-button type="primary" @click="saveQuestions">保存组卷</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '/@/utils/request'

const page = ref(1)
const total = ref(0)
const list = ref([])
const showForm = ref(false)
const form = reactive({ id: 0, title: '', duration: 60, description: '' })
const showDesign = ref(false)
const designMode = ref('manual')
const questionBank = reactive({ single: [], multi: [], judge: [], blank: [], short: [] })
// per-type search keywords
const bankSearch = reactive({ single: '', multi: '', judge: '', blank: '', short: '' })
// per-type loading state
const bankLoading = reactive({ single: false, multi: false, judge: false, blank: false, short: false })
const selectedIds = reactive({ single: [], multi: [], judge: [], blank: [], short: [] })
// pagination for question bank per type
const bankPage = reactive({ single: 1, multi: 1, judge: 1, blank: 1, short: 1 })
const bankPageSize = 10
// remote total per type (from backend)
const bankTotalRemote = reactive({ single: 0, multi: 0, judge: 0, blank: 0, short: 0 })
// pagination for selected lists per type
const selPage = reactive({ single: 1, multi: 1, judge: 1, blank: 1, short: 1 })
const selPageSize = 10

const selectedTypes = computed(() => {
    return Object.keys(selectedIds)
        .filter((k) => (selectedIds[k] || []).length)
        .map((k) => ({ type: k, ids: selectedIds[k] }))
})

// helper: get paged items from questionBank[type]
function pagedBank(type) {
    const arr = questionBank[type] || []
    // if remote total is present, we fetch server pages and simply return the current page slice
    if (bankTotalRemote[type]) {
        // questionBank[type] holds concatenated pages; pick the local page slice
        const p = Math.max(1, bankPage[type] || 1)
        const start = (p - 1) * bankPageSize
        return (arr || []).slice(start, start + bankPageSize)
    }
    const kw = (bankSearch[type] || '').trim().toLowerCase()
    const filtered = kw ? arr.filter((q) => ((q.content || '') + ' ' + (q.analysis || '')).toLowerCase().includes(kw)) : arr
    const p = Math.max(1, bankPage[type] || 1)
    const start = (p - 1) * bankPageSize
    return filtered.slice(start, start + bankPageSize)
}

// helper: find question by id across all types
function getQuestionById(id) {
    for (const t of Object.keys(questionBank || {})) {
        const q = (questionBank[t] || []).find((x) => x.id === id)
        if (q) return q
    }
    return null
}

// helper: get paged selected question objects for a type
function pagedSelected(type) {
    const ids = selectedIds[type] || []
    const p = Math.max(1, selPage[type] || 1)
    const start = (p - 1) * selPageSize
    const slice = ids.slice(start, start + selPageSize)
    return slice.map((id) => getQuestionById(id) || { id, content: '[题目已删除]' })
}
function bankTotal(type) {
    const arr = questionBank[type] || []
    const kw = (bankSearch[type] || '').trim().toLowerCase()
    return kw ? arr.filter((q) => ((q.content || '') + ' ' + (q.analysis || '')).toLowerCase().includes(kw)).length : arr.length
}
const typeMap = { single: '单选', multi: '多选', judge: '判断', blank: '填空', short: '简答' }
const randomForm = reactive({ single: 0, multi: 0, judge: 0, blank: 0, short: 0 })
let currentPaperId = 0

function getList() {
    request.get('/admin/examPaper/index', { params: { page: page.value } }).then((res) => {
        if (res.code === 1) {
            list.value = res.data.data
            total.value = res.data.total
        }
    })
}
function openAdd() {
    Object.assign(form, { id: 0, title: '', duration: 60, description: '' })
    showForm.value = true
}
function openEdit(row) {
    Object.assign(form, row)
    showForm.value = true
}
function submit() {
    let data = { ...form }
    let url = data.id ? '/admin/examPaper/edit/' + data.id : '/admin/examPaper/add'
    request.post(url, data).then((res) => {
        if (res.code === 1) {
            ElMessage.success(res.msg)
            showForm.value = false
            getList()
        } else {
            ElMessage.error(res.msg)
        }
    })
}
function del(id) {
    ElMessageBox.confirm('确定删除该试卷？', '提示', { type: 'warning' }).then(() => {
        request.post('/admin/examPaper/delete/' + id).then((res) => {
            if (res.code === 1) {
                ElMessage.success(res.msg)
                getList()
            } else {
                ElMessage.error(res.msg)
            }
        })
    })
}
function openDesign(row) {
    currentPaperId = row.id
    showDesign.value = true
    designMode.value = 'manual'
    // reset bank and pagination state, then load first page for each type
    Object.keys(questionBank).forEach((k) => (questionBank[k] = []))
    Object.keys(bankTotalRemote).forEach((t) => (bankTotalRemote[t] = 0))
    Object.keys(bankPage).forEach((t) => (bankPage[t] = 1))
    Object.keys(typeMap).forEach((type) => fetchPage(type, 1))
    // 获取已选题目
    request.get('/admin/examPaper/detail/id/' + row.id).then((res) => {
        if (res.code === 1) {
            let qs = res.data.questions
            Object.keys(selectedIds).forEach((t) => (selectedIds[t] = []))
            qs.forEach((q) => {
                const t = q.type
                const qid = q.question_id
                if (!t || !Object.prototype.hasOwnProperty.call(selectedIds, t)) return
                selectedIds[t].push(qid)
            })
        }
    })
}
// fetch a specific page for a type from backend
function fetchPage(type, page = 1) {
    const params = { type, page, pageSize: bankPageSize }
    const kw = (bankSearch[type] || '').trim()
    if (kw) params.q = kw
    bankLoading[type] = true
    return request
        .get('/admin/examPaper/questionBank', params)
        .then((res) => {
            bankLoading[type] = false
            if (res.code === 1) {
                // debug log
                console.log('fetchPage', type, page, params, res)
                // store items for this type: replace on first page, concat on subsequent
                if (page === 1) {
                    questionBank[type] = res.data.items || []
                } else {
                    questionBank[type] = (questionBank[type] || []).concat(res.data.items || [])
                }
                bankTotalRemote[type] = res.data.total || 0
                // update total (we don't store total in a dedicated state; pagination reads bankTotal which will compute locally if needed)
                bankPage[type] = page
            }
            return res
        })
        .catch((err) => {
            bankLoading[type] = false
            throw err
        })
}
function saveQuestions() {
    // 组装题目
    let questions = []
    Object.keys(selectedIds).forEach((type) => {
        ;(selectedIds[type] || []).forEach((id) => {
            let q = (questionBank[type] || []).find((item) => item.id === id)
            if (q) {
                questions.push({ question_id: id, type, score: q.score })
            } else {
                questions.push({ question_id: id, type, score: 0 })
            }
        })
    })
    request.post('/admin/examPaper/saveQuestions/id/' + currentPaperId, { questions }).then((res) => {
        if (res.code === 1) {
            ElMessage.success(res.msg)
            showDesign.value = false
            getList()
        } else {
            ElMessage.error(res.msg)
        }
    })
}
async function ensureLoaded(type, need) {
    let loaded = (questionBank[type] || []).length
    let page = bankPage[type] || 1
    while (loaded < need && loaded < (bankTotalRemote[type] || Infinity)) {
        page++
        // await fetchPage which now returns a promise
        try {
            const res = await fetchPage(type, page)
            if (res && res.data && Array.isArray(res.data.items)) {
                loaded = (questionBank[type] || []).length
            } else {
                // nothing new
                break
            }
        } catch {
            // stop trying on error
            break
        }
        // safety: prevent infinite loop
        if (page > 100) break
    }
}

async function randomSelect() {
    Object.keys(selectedIds).forEach((t) => (selectedIds[t] = []))
    // use a set to avoid duplicates globally
    const used = new Set()
    for (const type of Object.keys(randomForm)) {
        const need = Math.max(0, Math.floor(randomForm[type]))
        // ensure we have at least `need` items loaded for this type
        await ensureLoaded(type, need)
        let arr = (questionBank[type] || []).map((q) => q.id)
        // filter out already used ids just in case
        arr = arr.filter((id) => !used.has(id))
        let n = Math.min(need, arr.length)
        for (let i = 0; i < n; i++) {
            let idx = Math.floor(Math.random() * arr.length)
            const id = arr[idx]
            selectedIds[type].push(id)
            used.add(id)
            arr.splice(idx, 1)
        }
        // reset selected pagination for this type
        selPage[type] = 1
        bankPage[type] = 1
    }
}
onMounted(getList)
</script>

<style scoped>
.exam-paper-list {
    max-width: 1000px;
    margin: 0 auto;
}
</style>
